
/*
 * GET home page.
 */

module.exports = function(schemas){
	var users = schemas.user;
	var topics = schemas.topic;
	var trends = schemas.trend;
	var votes = schemas.votes;
	var reports = schemas.reports;
	var _ = require('underscore');
	var async = require('async');
	var routes = {};

	function checkSession(req, res){
		if (req.session.passport.user === undefined){
			res.status(401).json({status: 'not logged in'});
		
			return false;
		} else {
			return req.session.passport.user;
		}
	};
	
	routes.logout = function(req, res){
		req.session.passport.user = undefined;
		res.status(200).json({status: 'logged out'});
	};
		
	
	function getStat(obj, callback) {
		var ageGroups = {
			0 : 18,
			19 : 27,
			28 : 36,
			37 : 45,
			46 : 54,
			55 : 200
		};
		
		findTrend({trendName: obj.trendName}, '', function(err, record){
			if(err){
				callback(err);
				return;
			}
			
			if(record.length){
				obj.topicName = record[0].topicName || "";
				obj.created = record[0].created || "";
				obj.createdBy = record[0].createdBy || "";
				obj.votes = record[0].votes || "";
				obj.downvotes = record[0].downvotes || "";
			}
			
			findVotes({trendName: obj.trendName}, '', function(err, votes){
				var users = [];
				
				_.each(votes, function(vote){
					users.push({email: vote.votedBy});
				});
				
				async.each(users, getUserByEmail, function (err) {
					var males = _.where(users, {gender: 'male'}).length;
					var females = _.where(users, {gender: 'female'}).length;
					var birthdays = _.pluck(users, 'birthday');
					var ages = [];
					var agesMap = {};
					var agesUniq, mostPopularAge;
					
					if (err) {
						console.log(err);
						return;
					}
					
					obj.meta_summary = {};
					
					_.each(birthdays, function(birthday){
					    var diff, ageDate, age;

						if(birthday){ 
							diff = Date.now() - birthday;
							ageDate = new Date(diff); // miliseconds from epoch
							age = Math.floor(Math.abs(ageDate.getUTCFullYear() - 1970));
							
							if(!agesMap[age]){
								agesMap[age] = 1;
							} else {
								agesMap[age] += 1;
							}
							
							ages.push(age);
						}
					});
					
					agesUniq = Object.keys(agesMap);
					
					for(var i = 0; i < agesUniq.length; i++){
						if(!mostPopularAge){
							mostPopularAge = agesUniq[i];
						} else {
							if(agesMap[agesUniq[i]] > agesMap[mostPopularAge] || (agesMap[agesUniq[i]] === agesMap[mostPopularAge] && agesUniq[i] < mostPopularAge) ){
								mostPopularAge = agesUniq[i];
							}
						}
					}
					
					for(minAge in ageGroups){
						if(mostPopularAge > minAge && mostPopularAge < ageGroups[minAge]){
							obj.meta_summary.age = minAge + '-' + ageGroups[minAge];
						}
					}
					
					if(males > females){
						obj.meta_summary.gender = 'Male';
					} else if(males < females){
						obj.meta_summary.gender = 'Female';
					} else {
						obj.meta_summary.gender = 'Both';
					}
					
					obj.meta_summary.location = 'TBA';
					
  					callback(null, obj);
				});
			});
		});
	};
	
	function findVotes(query, sort, callback){
		votes.find(query)
		.setOptions({sort: sort})
		.exec(function(err, record){
			callback(err, record);
		});
	};
		
	function getUserByEmail(obj, callback){
		users.findOne({email: obj.email})
		.exec(function(err, user){
			if(user){
				obj.userLocation = user.userLocation;
				obj.birthday = user.birthday;
				obj.gender = user.gender;
			}
			
			callback(err, obj);
		});
	};
	
	function getUser(obj, callback){
		user.find({username: obj.username})
		.exec(function(err, record){
			callback(err, record);
		});
	};
	
	function findReport(query, callback){
		reports.find(query)
		.exec(function(err, record){
			callback(err, record);
		});
	};
	
	function findTopic(query, callback){
		topics.find(query)
		.exec(function(err, record){
			callback(err, record);
		});
	};
	
	function findTrend(query, sort, callback){
		trends.find(query)
		.setOptions({sort: sort})
		.exec(function(err, record){
			callback(err, record);
		});
	};
	
	function newTopic(topicName, user, res, callback){
		var new_topic = {
			topicName: topicName,
			created: new Date().getTime(),
			createdBy: user
		}
		
		var topic = new topics(new_topic);
	
		topic.save(function(err){
			if (err){
				console.log(err);
				if(res)
					res.status(500).json({status: 'fail'});
			} else {
				if(res)
					res.json({status: 'success'});
			}
		});
	};

	function updateTotal(trendName, value, res){
		var votes, downvotes;
	
		if(trendName){
			trends.find({trendName: trendName})
			.exec(function(err, record){
				if(err){
					res.json({status: 'error', message: 'database access error'});
					return null;
				} else {
					if(value > 0){
						votes = ++record[0].votes;
						downvotes = record[0].downvotes;
					} else {
						votes = record[0].votes;
						downvotes = ++record[0].downvotes;
					}
				
					trends.update({ trendName: trendName }, { votes: votes, downvotes: downvotes }, function (err, numberAffected, raw) {
						if (err){
							console.log(err);
							res.json({status: 'error', message: 'database access error'});
						} else {
							res.json(record[0]);
						}
					});
				}
			});
		}
	};

	routes.index = function(req, res){
		res.sendfile(req.abs_path + '/views/site_index.html');
	};
	
	routes.error = function(req, res){
		res.status(200).json({
			  app: 'TrendSettr',
			  ver: '0.0.2',
			  status: 'Error!'
		});
	}
	

	routes.addUser = function(req, res){
		
		var new_user = {
			username : JSON.parse(req.headers.json)["username"],
			password : JSON.parse(req.headers.json)["password"],
			service: JSON.parse(req.headers.json)["service"],
			email: JSON.parse(req.headers.json)["email"]
		};
		
		if(!new_user.email){
			res.json({status: 'error', message: 'Email is missing'});
		} else if(!new_user.service && !new_user.password){
			res.json({status: 'error', message: 'password or service should be provided'});
		} else {
			users.find({email: new_user.email})
			.exec(function(err, record){
				// if no users with this username
				if(!err && !record.length){
					var user = new users(new_user);
					user.save(function(err){
						if (err){
							console.log(err);
							res.status(500).json({status: 'fail'});
						} else {
							res.json({status: 'success'});
						}
					});
				} else {
					res.json({status: 'error', message: 'username with email ' + new_user.email + ' already exists'});
				}
			});
		}
	};
	
	routes.updatePoints = function(req, res){
		
		users.find()
		.exec(function(err, users){
			_.each(users, function(user){
				var points = 0;
				
				findTrend({createdBy: user.email}, 'votes', function(err, trend_record){
					if(!err && trend_record.length){
						_.each(trend_record, function(model){
							points += model.votes - model.downvotes;
						});
					}
				
					user.points = points;
					user.save();
				});
			});
		});
	};
	
	routes.user = function(req, res){
		var email = checkSession(req, res);
		
		if(email){
			users.findOne({email: email})
			.exec(function(err, user){
				var points = 0;
				
				if(user){
					findTrend({createdBy: email}, 'votes', function(err, trend_record){
						if(!err && trend_record.length){
							_.each(trend_record, function(model){
								points += model.votes - model.downvotes;
							});
						}
						
						user.points = points;
						user.save();
						
						res.json({'email': email, 'name': user.username, 'rank': user.rank, 'location': user.userLocation, 'gender': user.gender, 'birthday': user.birthday, 'picture': user.picture});
					});
				}
			});
		}
	};

	routes.users = function(req, res){
		users.find()
		.exec(function(err, users){
			if(err){
				console.log(err);
				res.status(500).json({status: 'failure'});
			} else {
				res.json(users);
			}
		});
	};

	routes.topics = function(req, res){
		var user = checkSession(req, res);
	
		if(user){
			topics.find()
			.setOptions({sort: 'votes'})
			.exec(function(err, record){
				if(!err && record.length){
					res.json(record);
				} else {
					res.json({status: 'error', message: 'no topics were found'});
				}
			});
		}
	};

	routes.topicsByUser = function(req, res){
		var user = checkSession(req, res);
	
		if(user){
			topics.find({createdBy: user})
			.setOptions({sort: 'created'})
			.exec(function(err, record){
				if(!err && record.length){
					res.json(record);
				} else {
					res.json({status: 'error', message: 'user doesn\'t have any topics'});
				}
			});
		}
	};
	
	
	routes.addTopic = function(req, res){
		var user = checkSession(req, res);
		var topicName = JSON.parse(req.headers.json)["topicName"];
		//var topicName = req.body.topicName;
	
		if(user && topicName){
			findTopic({topicName: topicName}, function(err, record){
				if(!err && !record.length){
					newTopic(topicName, user, res);
				} else {
					res.json({status: 'error', message: 'topic ' + new_topic.topicName  + ' is already exists'});
				}
			});
		} else if(!new_topic.topicName){
			res.json({status: 'error', message: 'topicName property is missing from the request'});
		}
	};
	
	routes.deleteTrendsByTopic = function(req, res){
		var user = checkSession(req, res);
		var topicName = req.param('topicName');
		
		if(user && topicName){
			trends.find({topicName: topicName})
			.exec(function(err, record){
				var l = record.length;
				
				if(!err && record.length){
					_.each(record, function(model){
						model.remove();
					});
					
					return res.json({status: 'success', message: l + ' records were deleted from Trends under ' + topicName + ' topic'});
				} else if(!record.length){
					res.json({status: 'error', message: 'no trends in topic ' + topicName});
				} else {
					console.log(err);
					res.json({status: 'error', message: 'database access error'});
				}	
			});
		} else if(!topicName){
			res.json({status: 'error', message: 'topicName property is missing from the request'});
		}
	};
	
	routes.deleteTopic = function(req, res){
		var user = checkSession(req, res);
		var topicName = req.param('topicName');
		
		if(user && topicName){
			routes.deleteTrendsByTopic(req, res);
			
			findTopic({topicName: topicName}, function(err, record){
				if (err){
					console.log(err);
					res.json({status: 'error', message: 'database access error'});
				}	
								
				if(record.length){
					_.each(record, function(model){
						model.remove();
					});
				
					return res.json({status: 'success', message: 'Topic ' + topicName + ' was deleted!'});
				} else if(!err && !record.length){
					res.json({status: 'error', message: 'Topic ' + topicName + ' not found!'});
				} 
			});
		} else if(!topicName){
			res.json({status: 'error', message: 'topicName property is missing from the request'});
		}
	};
	
	routes.trends = function(req, res){
		var user = checkSession(req, res);
	
		if(user){
			findTrend({}, 'votes', function(err, record){
				if(!err && record.length){
					res.json(record);
				} else {
					res.json({status: 'error', message: 'no trends were found'});
				}
			});
		}
	};

	routes.trendsByUser = function(req, res){
		var user = checkSession(req, res);
	
		if(user){
			findTrend({createdBy: user}, 'votes', function(err, record){
				if(!err && record.length){
					res.json(record);
				} else {
					res.json({status: 'error', message: 'user doesn\'t have any trends'});
				}
			});
		}
	};
	
	routes.votesByDay_reroute = function(req,res){
		routes.votesByDay(req,res,-1);
	}
	
	routes.votesByDay = function(req, res, rerouted){
		var user = checkSession(req, res);
		var trendName;
		if(rerouted != +rerouted){
			trendName = req.param('trendName');
		}else{
			trendName = JSON.parse(req.headers.json)["trendName"];
		}
		var response = [];
		
		if(user && trendName){
			votes.find({trendName: trendName})
			.setOptions({sort: 'dateVoted'})
			.exec(function(err, record){
				if(err){
					res.json({status: 'error', message: 'database access error'});
					return;
				}
				
				if(record.length){
					async.each(record, function(model, callback){
						var date = new Date(model.dateVoted).setHours(1, 0, 0, 0);
						var row = _.where(response, {date: date});
						
						if(!row.length){
							row = {
								date: date,
								votes: model.voted > 0 ? model.voted : 0,
								downvotes: model.voted < 0 ? -model.voted : 0
							};
							
							response.push(row);
						} else {
							row[0].votes += model.voted > 0 ? model.voted : 0;
							row[0].downvotes += model.voted < 0 ? -model.voted : 0;
						}
						
						callback(null, response);
					}, function(err){
						if(err){
							console.log(err)
							res.json({status: 'error', message: 'database access error'});
							return
						}
						
						res.json(response);
					});
				} else {
					res.json({status: 'error', message: 'no data'});
				}
			});
		}
	};
	
	//TODO: see friendVote description in app.js
	routes.friendVote = function(req, res){
		var user = checkSession(req, res);
		var trend_to_check_friends_for = JSON.parse(req.headers.json)["trendName"];
	};
	
	//TODO: see getReport description in app.js
	routes.getReport = function(req, res){
		var user = checkSession(req, res);
		var trend_to_check_reports_for = JSON.parse(req.headers.json)["trendName"];
	};
	
	//Right now it just puts a report in for the trend. Basically copied the addTrend code
	routes.report = function(req,res){
		var user = checkSession(req, res);
		var new_report = {
			trendName: JSON.parse(req.headers.json)["trendName"],
			created: new Date().getTime(),
			createdBy: user,
			report: JSON.parse(req.headers.json)["report"]
		}
		
		if(user && new_report.trendName){
			findReport({trendName: new_report.trendName, createdBy: user}, function(err, record){
				if(!err){
					//Make sure that there aren't any reports already in the db for this trend and user
					if(!record.length){
						var report = new reports(new_report);
						report.save(function(err){
							if (err){
								console.log(err);
								res.status(500).json({status: 'fail'});
							} else {
								res.json({status: 'success'});
							}
						});
					}
				} else {
					res.json({status: 'error', message: 'database access error'});
				}
			});
		} else if(!new_report.trendName){
			res.json({status: 'error', message: 'trendName property is missing from the request'});
		}
	}
	
	routes.addTrend = function(req, res){
		var user = checkSession(req, res);
		var new_trend = {
			topicName: JSON.parse(req.headers.json)["topicName"],
			trendName: JSON.parse(req.headers.json)["trendName"],
			created: new Date().getTime(),
			createdBy: user,
			votes: 0,
			downvotes: 0
		}
	
		if(user && new_trend.trendName && new_trend.topicName){
			findTopic({topicName: new_trend.topicName}, function(err, record){
				if(!err){
					if(!record.length)
						newTopic(new_trend.topicName, user);
					
					findTrend({trendName: new_trend.trendName}, '', function(err, record){
						if(!err && !record.length){
							
							//TODO: Need to do a google image search here. 
							//Return the first picture found and store it in trend.imagesrc
							var trend = new trends(new_trend);
				
							trend.save(function(err){
								if (err){
									console.log(err);
									res.status(500).json({status: 'fail'});
								} else {
									res.json({status: 'success'});
								}
							});
						} else {
							res.json({status: 'error', message: 'topic ' + new_trend.trendName  + ' is already exists'});
						}
					});	
				} else {
					res.json({status: 'error', message: 'database access error'});
				}
			});
		} else if(!new_trend.trendName){
			res.json({status: 'error', message: 'trendName property is missing from the request'});
		}  else if(!new_trend.topicName){
			res.json({status: 'error', message: 'topicName property is missing from the request'});
		} 
	};

	routes.votes = function(req, res){
		var user = checkSession(req, res);
		var user_array = {};
		
		if(user){
			users.find().exec(function(err,person){
				//TODO: I know there is a better way to do this with foreign keys in mongo or something
				//This basically attaches the creating user's picture to each trend.
				//Need to move onto other things. Needs to be redone in query... GOTO: 10
				_.each(person, function(row){
					user_array[row["email"]] = row["picture"];
				});
				//10
				votes.find({votedBy: user})
				.setOptions({sort: 'dateVoted'})
				.exec(function(err, record){
					var clone = [];
					if(!err && record.length){
						
						_.each(record, function(row){
							var obj = {};
							var keys = Object.keys(row._doc);
							var key;
							
							for(i = 0; i < keys.length; i++){
								key = keys[i];
								obj[key] = row[key];
							}
							
							clone.push(obj);
						});
						
						async.each(clone, getStat, function (err) {
							if (err) {
								console.log(err);
								return;
							}
						  
							_.each(clone, function(row){
								row["picture"] = user_array[row["createdBy"]];
							});
							
		  					res.json(clone);
						});
					} else {
						res.json({status: 'error', message: 'user doesn\'t have any votes'});
					}
				});
			});
		}
	};
	
	routes.votesAll = function(req, res){
		var user = checkSession(req, res);
		
		if(user){
			votes.find()
			.exec(function(err, record){
				if(!err && record.length){
					async.each(record, getTrend, function (err) {
					  if (err) {
					    console.log(err);
					    return;
					  }
					  
					  res.json(record);
					});
				} else {
					res.json({status: 'error', message: 'user doesn\'t have any votes'});
				}
			});
		}
	};
	
	
	
	routes.vote = function(req, res, voted){
		var user = checkSession(req, res);
		var voted = voted = +voted ? voted : 1;
		
		var new_vote = {
			//Sorry Dmitry. The post params in the body stopped working. Put everything in the header instead
			trendName: JSON.parse(req.headers.json)["trendName"],
			dateVoted: new Date().getTime(),
			votedBy: user,
			voted: voted
		}
	
		if(user && new_vote.trendName){
			trends.find({trendName: new_vote.trendName})
			.exec(function(err, record){
				if (record.length){
					votes.find({trendName: new_vote.trendName, votedBy: user})
					.exec(function(err, record){
						if(!record.length){
							var vote = new votes(new_vote);
				
							vote.save(function(err){
								if (err){
									console.log(err);
									res.status(500).json({status: 'fail'});
								} else {
									updateTotal(new_vote.trendName, new_vote.voted, res);
									//res.json({status: 'success'});
								}
							});
						} else {
							res.json({status: 'error', message: 'user ' + user + ' has already voted for ' + new_vote.trendName});	
						} 
			
						if(err){
							res.json({status: 'error', message: 'there was an error saving the vote'});
						}
					});
				} else if(!record.length) {
					res.json({status: 'error', message: 'trend ' + new_vote.trendName + ' doesn\'t exist'});
				} else {
					res.json({status: 'error', message: 'database access error'});
				}
			});
		} else if(!new_vote.trendName){
			res.json({status: 'error', message: 'topicName property is missing from the request'});
		}
	};

	routes.downVote = function(req, res){
		routes.vote(req, res, -1);
	};
	
	routes.notVotedTrends = function(req, res){
		var user = checkSession(req, res);
		var i = 0;
		var votesArr = [];
		
		if(user){
			votes.find({votedBy: user})
			.exec(function(err, votesRecord){
				if(!err){
					while(i < votesRecord.length){
						votesArr.push(votesRecord[i].trendName);
						i++;
					}
					
					users.find()
					.sort({'points': -1})
					.limit(100).
					exec(function(err, users){
						trends.find()
						.where('trendName').nin(votesArr)
						.exec(function(err, trendsRecord){
							var to_return = [];
						
							if(!err && trendsRecord.length){
								_.each(users, function(user){
									var ranked = _.where(trendsRecord, {createdBy: user.email});
									
									_.each(ranked, function(model){
										var obj = {
											topicName: model.topicName,
											trendName: model.trendName,
											created: model.created,
											createdBy: model.createdBy,
											_id: model._id
										};
										to_return.push(obj);
									});
								});
							
								res.json(to_return);
							} else if(!err && !trendsRecord.length){
								res.json({status: 'ok', message: 'no trends were found'});
							} else {
								res.json({status: 'error', message: 'database access error'});
							}
						});
					});
				} else {
					res.json({status: 'error', message: 'user doesn\'t have any votes'});
				}
			});
		}
	};
	
	return routes;
}